package logica.locacao;

import java.util.ArrayList;
import java.util.List;

import logica.util.Constantes;
import logica.veiculo.Acessorio;

/**
 * Especifica todas as caracteristicas do plano de locacao: quais veiculos estao disponiveis
 * (marcas e modelos), e com que acessorios, bem como se eh ou nao segurado.
 * @author - Guilherme Santos G. Baptista em 09/10/2010
 */

public class Plano {

	private String codigo;
	private List<String[]> marcas;
	private Acessorio[] acessorios;
	private Seguro seguro;
	private double potencia;
	private static final int UMA_VEZ = 1;
	
	/**
	 * 
	 * Construtor de Plano.
	 * @param marcas String[] - As marcas que esse plano oferece
	 * @param modelos String[] - Os modelos que esse plano oferece
	 * @param acessorios Acessorio[] - Os acessorios que esse plano oferece
	 * @param seguro Seguro - O seguro que esse plano contem, se seguro nao for igual a <i>null</i>
	 * @param potencia float - O valor de potencia que os veiculos do plano devem ter
	 * 
	 */
	public Plano(String codigo, String[] marcas, String[] modelos, Acessorio[] acessorios, Seguro seguro, double potencia ) throws Exception{

		if ( codigo == null || codigo.trim().isEmpty() || codigo.length() != Constantes.QTDE_DIGITOS_COD_PLANO ){
			throw new Exception("Codigo invalido!");
		}
		
		for ( int d=0; d<codigo.length(); d++ ){
			if ( !Character.isDigit(codigo.charAt(d)) ){
				throw new Exception("Codigo invalido!");
			}
		}
		
		if ( marcas == null || modelos == null || acessorios == null ){
			throw new Exception("Parametro(s) invalido(s)!");
		}

		if ( acessorios.length >= Constantes.QTDE_ACESSORIOS_POR_PLANO ){
			throw new Exception("Quantidade de acessorios invalida!");
		}
		
		if ( potencia<= 0 ){
			throw new Exception("Potencia invalida!");
		}
		
		this.codigo = codigo;
		
		this.gerarRelacaoMarcasXModelos(marcas, modelos);

		this.acessorios = new Acessorio[Constantes.QTDE_ACESSORIOS_POR_PLANO];

		for ( int i=0; i<acessorios.length; i++ ){
			this.acessorios[i] = acessorios[i];
		}
		
		this.seguro = seguro;
		
		this.potencia = potencia;
	}
	
	/**
	 * Construtor de Plano.
	 * @param marcas String[] - As marcas que esse plano oferece
	 * @param modelos String[] - Os modelos que esse plano oferece
	 * @param acessorios Acessorio[] - Os acessorios que esse plano oferece
	 */
	public Plano(String codigo, String[] marcas, String[] modelos, Acessorio[] acessorios, double potencia) throws Exception{
		this(codigo, marcas,modelos,acessorios,null,potencia);
	}
	
	/**
	 * Retorna o codigo desse plano.
	 * @return String - O codigo desse plano
	 */
	public String getCodigo(){
		return this.codigo;
	}
	
	/**
	 * Determina um novo codigo para esse plano.
	 * @param codigo String - O novo codigo a ser determinado
	 * @throws Exception Excecao caso o codigo nao seja composto somente por inteiros
	 * e nao tenha a quantidade de digitos correta
	 */
	public void setCodigo(String codigo) throws Exception{
		if ( codigo == null || codigo.trim().isEmpty() || codigo.length() != Constantes.QTDE_DIGITOS_COD_PLANO ){
			throw new Exception("Codigo invalido!");
		}
		for ( int d=0; d<codigo.length(); d++ ){
			if ( !Character.isDigit(codigo.charAt(d)) ){
				throw new Exception("Codigo invalido!");
			}
		}
		this.codigo = codigo;
	}
	
	/**
	 * Retorna um array de marcas oferecidas pelo plano.
	 * @return String[] - Um array de marcas
	 */
	public String[] getMarcas(){
		String[] retorno = new String[this.marcas.size()];
		for ( int i=0; i<this.marcas.size(); i++ ){
			retorno[i] = this.marcas.get(i)[0];
		}
		return retorno;
	}
	
	/**
	 * Retorna um array de modelos oferecidos pelo plano.
	 * @return String[] - Um array de modelos disponiveis 
	 */
	public String[] getModelos(){
		List<String> modelos = new ArrayList<String>();
		for ( int i=0; i<this.marcas.size(); i++ ){
			for ( int j=1; j<this.marcas.get(i).length; j++ ){
				if ( !(this.marcas.get(i)[j] == null) ){
					modelos.add(this.marcas.get(i)[j]);
				}
			}
		}
		
		String[] retorno = new String[modelos.size()];
		for ( int i=0; i<retorno.length; i++ ){
			retorno[i] = modelos.get(i);
		}
		return retorno;
	}
	
	/**
	 * Retorna uma lista de arrays, onde em cada primeira posicao do array ha uma marca, e nas
	 * proximas, os modelos associados a esta marca.
	 * @return List(String[]) - Uma lista de arrays com as marcas e modelos
	 */
	public List<String[]> getMarcaXModelos(){
		return this.marcas;
	}
	
	/**
	 * Determina todo um novo esquema de marcas e modelos.
	 * @param marcas String[] - Array com todas as marcas
	 * @param modelos String[] - Array com todos os modelos
	 * @throws Exception Excecao caso parametro(s) seja(m) invalido(s)!
	 */
	public void setMarcaXModelos(String[] marcas, String[] modelos) throws Exception{
		if ( marcas == null || modelos == null ){
			throw new Exception("Marca(s) e/ou modelo(s) invalido(s)!");
		}
		this.gerarRelacaoMarcasXModelos(marcas, modelos);
	}
	
	/**
	 * Adiciona uma nova marca e/ou modelo(s).
	 * Se a marca ja existir, somente novos modelos sao adicionados. Caso nao exista,
	 * ambos sao adicionados. Nao ha modelos nem marcas duplicados.
	 * @param marca String[] - A marca que sera adicionada ou cujos modelos serao adicionados
	 * @param modelos String[] - Os modelos que serao adicionados
	 * @throws Exception Excecao caso nao haja mais espaco para modelos de uma certa marca
	 */
	public void adicionarMarcaEModelos(String marca, String[] modelos) throws Exception{
		if ( marca == null || modelos == null ){
			throw new Exception("Marca e/ou modelos invalidos!");
		}
		
		
		boolean marcaExiste = false;
		boolean modeloExiste = false;
		boolean modeloInserido = false;
		
		for ( int i=0; i<this.marcas.size(); i++ ){
			if ( marca.equals(this.marcas.get(i)[0]) ){
				marcaExiste = true;

				for ( int j=0; j<modelos.length; j++ ){
					modeloExiste = false;
					modeloInserido = false;
					for ( int m=1; m<this.marcas.get(i).length; m++ ){
						 if ( modelos[j].equals(this.marcas.get(i)[m]) ){
							modeloExiste = true;
						}
					}
					if ( !modeloExiste ){
						for ( int n=1; n<this.marcas.get(i).length; n++ ){
							if ( this.marcas.get(i)[n] == null ){
								this.marcas.get(i)[n] = modelos[j];
								modeloInserido = true;
								break;
							}
						}
						if ( !modeloInserido ){
							throw new Exception("Nao houve espaco para o novo modelo "+modelos[j]+"!");
						}
					}
				}
				
			}
		}
		
		if ( !marcaExiste ){
			String[] novaEntrada = new String[Constantes.QTDE_MODELOS_POR_MARCA];
			this.marcas.add(novaEntrada);
			this.marcas.get(this.marcas.indexOf(novaEntrada))[0] = marca;
			
			int indiceMarca = 0;
			for ( int k=0; k<this.marcas.size(); k++ ){
				if ( this.marcas.get(k)[0].equals(marca) ){
					indiceMarca = k;
				}
			}
			
			for ( int l=0; l<modelos.length; l++ ){
				modeloExiste = false;
				modeloInserido = false;
				for ( int m=1; m<this.marcas.get(indiceMarca).length; m++ ){
					 if ( modelos[l].equals(this.marcas.get(indiceMarca)[m]) ){
						modeloExiste = true;
					}
				}
				if ( !modeloExiste ){
					for ( int n=1; n<this.marcas.get(indiceMarca).length; n++ ){
						if ( this.marcas.get(indiceMarca)[n] == null ){
							this.marcas.get(indiceMarca)[n] = modelos[l];
							modeloInserido = true;
							break;
						}
					}
					if ( !modeloInserido ){
						throw new Exception("Nao houve espaco para o novo modelo "+modelos[l]+"!");
					}
				}
			}
		}
	}
	
	/**
	 * Adiciona nova marca, caso nao exista ainda, e novo modelo, tambem caso ja nao exista.
	 * @param marca String - A marca a ser adicionada
	 * @param modelo String - O modelo a ser adicionado
	 * @throws Exception Excecao caso nao haja espaco para novos modelos
	 */
	public void adicionarMarcaEModelo(String marca, String modelo) throws Exception{
		if ( marca == null || modelo == null ){
			throw new Exception("Marca e/ou modelo invalido(s)!");
		}
		String[] arrayModelo = {modelo};
		this.adicionarMarcaEModelos(marca, arrayModelo);
	}
	
	/**
	 * Remove a marca, deletando tambem todos os modelos associados a ela.
	 * @param marca String - A marca a ser deletada
	 */
	public void removerMarca(String marca) throws Exception{
		if ( marca == null ){
			throw new Exception("Marca invalida!");
		}
		
		boolean marcaExiste = false;
		final List<String[]> antiga = this.marcas;
		
		for ( int i=0; i<this.marcas.size(); i++ ){
			if ( this.marcas.get(i)[0].equals(marca) ){
				marcaExiste = true;
				this.marcas.remove(this.marcas.get(i));
			}
		}
		
		if ( !marcaExiste ){
			this.marcas = antiga;
			throw new Exception("A marca solicitada para remocao nao existe!");
		}
	}
	
	/**
	 * Remove um certo modelo de uma determinada marca. 
	 * @param marca String - A marca cujo modelo sera deletado
	 * @param modelo - O modelo a ser removido
	 * @throws Exception Excecao de parametros invalidos
	 */
	public void removerModeloDaMarca(String marca, String modelo) throws Exception{
		if ( marca == null || modelo == null ){
			throw new Exception("Marca e/ou modelos invalidos!");
		}
		
		final List<String[]> antiga = this.marcas;
		boolean ficaraVazio = true;
		boolean marcaExiste = false;
		boolean modeloExiste = false;
		String[] aRemover = null;
		
		for ( int i=0; i<this.marcas.size(); i++ ){
			if ( this.marcas.get(i)[0].equals(marca) ){
				marcaExiste = true;
				for ( int j=1; j<this.marcas.get(i).length; j++ ){
					if ( this.marcas.get(i)[j] != null && this.marcas.get(i)[j].equals(modelo) ){
						modeloExiste = true;
						this.marcas.get(i)[j] = null;
					}
					else if ( this.marcas.get(i)[j] != null ){
						ficaraVazio = false;
					}
				}
				if ( ficaraVazio && modeloExiste ){
					aRemover = this.marcas.get(i);
				}
			}
		}
		if ( !marcaExiste || !modeloExiste ){
			this.marcas = antiga;
			throw new Exception("Marca e/ou modelo solicitado(s) para remocao nao existe(m)!");
		}
		if ( ficaraVazio && aRemover != null ){
			this.marcas.remove(aRemover);
		}
	}
	
	/**
	 * Retorna um array de acessorios oferecidos pelo plano.
	 * @return Acessorio[] - Um array de acessorios
	 */
	public Acessorio[] getAcessorios(){
		return this.acessorios;
	}
	
	/**
	 * Determina um novo array de acessorios oferecidos pelo plano.
	 * @param acessorios Acessorio[] - Um novo array de acessorios
	 * @throws Exception Excecao de parametros invalidos
	 */
	public void setAcessorios(Acessorio[] acessorios) throws Exception{
		if ( acessorios == null || acessorios.length != Constantes.QTDE_ACESSORIOS_POR_PLANO ){
			throw new Exception("Acessorios invalidos!");
		}
		this.acessorios = acessorios;
	}
	
	/**
	 * Adiciona novo(s) acessorio(s), caso haja espaco, sem duplicacao.
	 * @param acessorios Acessorio[] - Array de acessorios a serem adicionados
	 * @throws Exception Excecao caso nao haja mais espaco para novos acessorios
	 */
	public void adicionarAcessorios(Acessorio[] acessorios) throws Exception{
		if ( acessorios == null ){
			throw new Exception("Acessorios invalidos!");
		}
		
		boolean acessorioExiste = false;
		boolean acessorioInserido = false;
		
		for ( int i=0; i<acessorios.length; i++ ){
			acessorioExiste = false;
			acessorioInserido = false;
			for ( int j=0; j<this.acessorios.length; j++ ){
				if ( acessorios[i] == this.acessorios[j] ){
					acessorioExiste = true;
				}
			}
			if ( !acessorioExiste ){
				for ( int k=0; k<this.acessorios.length; k++ ){
					if ( this.acessorios[k] == null ){
						this.acessorios[k] = acessorios[i];
						acessorioInserido = true;
						break;
					}
				}
				if ( !acessorioInserido ){
					throw new Exception("Nao houve espaco para o novo acessorio "+acessorios[i].getDescricao()+"!");
				}
			}
		}
	}
	
	/**
	 * Adiciona um novo acessorio, caso haja espaco, sem duplicacao.
	 * @param acessorio Acessorio - Um novo acessorio a ser adicionado
	 * @throws Exception Excecao caso nao haja mais espaco para o novo acessorio
	 */
	public void adicionarAcessorio(Acessorio acessorio) throws Exception{
		if ( acessorio == null ){
			throw new Exception("Acessorio invalido!");
		}
		Acessorio[] arrayAcessorio = {acessorio};
		this.adicionarAcessorios(arrayAcessorio);
	}
	
	/**
	 * Remove um acessorio especificado.
	 * @param acessorio Acessorio - O acessorio a ser removido
	 * @throws Exception Excecao de parametros invalidos
	 */
	public void removerAcessorio(Acessorio acessorio) throws Exception{
		if ( acessorio == null ){
			throw new Exception("Acessorio invalido!");
		}
		for ( int i=0; i<this.acessorios.length; i++ ){
			if ( this.acessorios[i] == acessorio ){
				this.acessorios[i] = null;
			}
		}
	}
	
	/**
	 * Retorna um seguro, dentre os disponiveis.
	 */
	public Seguro getSeguro() throws Exception{
		if ( this.seguro == null ){
			throw new Exception("Nao contem seguro!");
		}
		return this.seguro;
	}
	
	/**
	 * Determina um novo seguro para o plano.
	 * @param seguro Seguro - Um novo seguro para o plano
	 * @throws Exception Excecao de parametros invalidos
	 */
	public void setSeguro(Seguro seguro) throws Exception{
		if ( seguro == null ){
			throw new Exception("Seguro invalido!");
		}
		this.seguro = seguro;
	}
	
	/**
	 * Remove o seguro do plano.
	 */
	public void removerSeguro(){
		this.seguro = null;
	}
	
	/**
	 * Gera um novo ArrayList<String[]> e organiza ele recebendo arrays de Strings correspontentes
	 * as marcas e aos modelos.
	 * @param marcas String[] - Array de marcas a serem oferecidas pelo plano
	 * @param modelos String[] - Array de modelos a serem oferecidos pelo plano
	 * @throws Exception Excecao caso a quantidade de modelos por marca seja incorreta
	 */
	private void gerarRelacaoMarcasXModelos(String[] marcas, String[] modelos) throws Exception{
		final List<String[]> antiga = this.marcas;
		
		int repeticoesEmSi = 0;
		int repeticoesNaOutra = 0;
		for ( int a=0; a<marcas.length; a++ ){
			repeticoesEmSi = 0;
			for ( int b=0; b<marcas.length; b++ ){
				if ( marcas[a].equals(marcas[b]) ){
					repeticoesEmSi++;
				}
			}
			if ( repeticoesEmSi != UMA_VEZ ){
				throw new Exception("Padrao incorreto! Ha marcas repetidas no array de marcas!");
			}
			repeticoesNaOutra = 0;
			for ( int c=0; c<modelos.length; c++ ){
				if ( marcas[a].equals(modelos[c]) ){
					repeticoesNaOutra++;
				}
			}
			if ( repeticoesNaOutra != repeticoesEmSi ){
				throw new Exception("Padrao incorreto! Cada marca deve ter estritamente 1 imagem no array de modelos!");
			}
		}
		
		boolean validar = false;
		for ( int d=0; d<marcas.length; d++ ){
			if ( modelos[0].equals(marcas[d]) ){
				validar = true;
			}
		}
		if ( !validar ){
			throw new Exception("Padrao incorreto! Nao deve haver modelos antes da primeria marca no array de modelos!");
		}
		
		this.marcas = new ArrayList<String[]>();
		
//		System.out.println("(>>>PRIMEIRA ETAPA<<<)");
		for ( int i=0; i<marcas.length; i++ ){
			this.marcas.add(new String[Constantes.QTDE_MODELOS_POR_MARCA]);
			this.marcas.get(i)[0] = marcas[i];
//			System.out.println("--- adicionando "+marcas[i]+" na lista de Marcas");
		}
		
		String marcaAtual = null;
		boolean ehModelo = false;
		boolean modeloInserido = false;
		
//		System.out.println("(>>>SEGUNDA ETAPA<<<)");
		for ( int j=0; j<modelos.length; j++ ){
//			System.out.println("j:"+j);
			modeloInserido = false;
			for ( int k=0; k<marcas.length; k++ ){
//				System.out.println("k:"+k);
//				System.out.printf("--- pegando "+modelos[j]+" e comparando com "+marcas[k]);
				if ( modelos[j].equals(marcas[k]) ){
					marcaAtual = modelos[j];
					ehModelo = false;
//					System.out.println("--- sao iguais.");
					break;
				}
				else{
					ehModelo = true;
//					System.out.println("--- sao diferentes.");
				}
			}
			
//			System.out.println("A marca Atual eh "+marcaAtual);

			if ( ehModelo ){
//				System.out.println("O modelo Atual eh "+modelos[j]);
//				System.out.println(">>>trabalhando com MODELO<<<");
				
				for ( int l=0; l<this.marcas.size(); l++ ){
//					System.out.println("l:"+l);
//					System.out.println("--- pegando "+this.marcas.get(l)[0]+" e comparando com "+marcaAtual);
					if ( marcaAtual.equals(this.marcas.get(l)[0]) ){
//						System.out.println("--- sao iguais. Pesquisando posicao correta.");
						for ( int m=1; m<this.marcas.get(l).length && !modeloInserido ; m++ ){
//							System.out.println("m:"+m);
//							System.out.print("--- posicao "+m);
							if ( this.marcas.get(l)[m] == null ){
//								System.out.println("--- esta posicao estah vazia!!!");
								this.marcas.get(l)[m] = modelos[j];
								modeloInserido = true;
//								System.out.println(">>>MODELO INSERIDO<<<");
							}
						}
						if ( !modeloInserido ){
//							System.out.println("Nao houve espaco na lista de posicoes para este modelo.");
							throw new Exception("Quantidade de modelos para cada marca nao pode ser superior a "+(Constantes.QTDE_MODELOS_POR_MARCA-1)+", logo ("+modelos[j]+") nao foi inserido!");
						}
					}
//					System.out.println("--- sao diferentes.");
				}
			}
		}
		for ( int x=0; x<this.marcas.size(); x++ ){
			validar = false;
			for ( int y=1; y<this.marcas.get(x).length; y++ ){
				if ( this.marcas.get(x)[y] != null ){
					validar = true;
				}
			}
			if ( !validar ){
				this.marcas = antiga;
				throw new Exception("Nao pode haver marcas sem pelo menos um modelo associado no array de modelos!");
			}
		}
	}
	
	/**
	 * Compara dois Planos, verificando se tem seguros com mesma cobertura e se oferecem
	 * as mesmas marcas, modelos e acessorios. Dois planos podem ser iguais mesmo com codigos diferentes.
	 */
	@Override
	public boolean equals(Object objeto){
		if ( !( objeto instanceof Plano )){
			return false;
		}
		
		Plano outro = (Plano) objeto;
		
		boolean segurosIguais = false;
		boolean acessoriosIguais = true;
		boolean marcasModelosIguais = true;
		
		//COMPARACAO DOS SEGUROS
		try{
			Seguro meuSeguro = this.getSeguro();
		}
		catch (Exception e){ // Se lancar excecao, eh porque nao tenho seguro.
			try{
				Seguro seuSeguro = outro.getSeguro();
			}
			catch ( Exception f ){ // Se lancar excecao novamente, eh porque ele nao tem seguro.
				segurosIguais = true; // Logo, o seguro de ambos eh IGUAL (null).
			}
		}
		try{
			if ( !segurosIguais ){ // Mas, se ambos os seguros nao sao iguais por serem ambos nulos,
				Seguro meuSeguro = this.getSeguro();
				Seguro seuSeguro = outro.getSeguro(); // se ambos tiverem seus atributos iguais, os seguros sao iguais.
				if ( meuSeguro.getCobertura() == seuSeguro.getCobertura() && 
						meuSeguro.getPorcentagem() == seuSeguro.getPorcentagem() ){
					segurosIguais = true;
				}
			}
		}
		catch ( Exception g ){} // No entanto se lancar excecao eh porque
							   //um dos dois nao tem seguro enquanto o outro tem, logo, eles sao diferentes.

		
		//COMPARACAO DOS ACESSORIOS
		boolean temImagem = false;
		
		if ( this.getAcessorios().length == outro.getAcessorios().length ){
			int minhasPosicoesVazias = 0;
			int suasPosicoesVazias = 0;
			
			for ( int i=0; i<this.getAcessorios().length; i++ ){
				if ( this.getAcessorios()[i] == null ){
					minhasPosicoesVazias++;
				}
			}
			for ( int i=0; i<outro.getAcessorios().length; i++ ){
				if ( outro.getAcessorios()[i] == null ){
					suasPosicoesVazias++;
				}
			}
			
			if ( minhasPosicoesVazias == suasPosicoesVazias ){
				for ( int i=0; i<this.getAcessorios().length; i++ ){
					temImagem = false;
					if ( !(this.getAcessorios()[i] == null) ){
						for ( int j=0; j<outro.getAcessorios().length; j++ ){
							if ( !(outro.getAcessorios()[j] == null) ){
								if ( this.getAcessorios()[i] == outro.getAcessorios()[j] ){
									temImagem = true;
								}
							}
						}
					}
					if ( this.getAcessorios()[i] != null && !temImagem ){
						acessoriosIguais = false;
						break;
					}
				}
				for ( int i=0; i<outro.getAcessorios().length; i++ ){
					temImagem = false;
					if ( !(outro.getAcessorios()[i] == null) ){
						for ( int j=0; j<this.getAcessorios().length; j++ ){
							if ( !(this.getAcessorios()[j] == null) ){
								if ( outro.getAcessorios()[i] == this.getAcessorios()[j] ){
									temImagem = true;
								}
							}
						}		
					}
					if ( this.getAcessorios()[i] != null && !temImagem ){
						acessoriosIguais = false;
						break;
					}
				}
			}
			else {
				acessoriosIguais = false;
			}
		}
		else{
			acessoriosIguais = false;
		}
		
		
		//COMPARACAO DAS MARCAS E MODELOS
		if ( this.marcas.size() == outro.getMarcaXModelos().size() ){

			for ( int i=0; i<this.marcas.size(); i++ ){
				temImagem = false;
				for ( int j=0; j<outro.getMarcaXModelos().size(); j++ ){
					if ( this.marcas.get(i)[0].equals(outro.getMarcaXModelos().get(j)[0]) ){
						temImagem = true;
					}
				}
				if ( !temImagem ){
					marcasModelosIguais = false;
				}
			}
			for ( int i=0; i<outro.getMarcaXModelos().size(); i++ ){
				temImagem = false;
				for ( int j=0; j<this.marcas.size(); j++ ){
					if ( outro.getMarcaXModelos().get(i)[0].equals(this.marcas.get(j)[0]) ){
						temImagem = true;
					}
				}
				if ( !temImagem ){
					marcasModelosIguais = false;
				}
			}
			
			for ( int x=1; x<this.marcas.size(); x++ ){
				for ( int y=1; y<this.marcas.get(x).length; y++ ){
					temImagem = false;
					if ( this.marcas.get(x)[y] != null ){
						for ( int z=0; z<outro.getMarcaXModelos().size(); z++ ){
							for ( int w=1; w<outro.getMarcaXModelos().get(z).length; w++ ){
								if ( outro.getMarcaXModelos().get(z)[w] != null ){
									if ( this.marcas.get(x)[y].equals(outro.getMarcaXModelos().get(z)[w]) ){
										temImagem = true;
									}
								}
							}
						}
						if ( !temImagem) {
							marcasModelosIguais = false;
							break;
						}
					}
				}
			}
			
			for ( int x=1; x<outro.getMarcaXModelos().size(); x++ ){
				for ( int y=1; y<outro.getMarcaXModelos().get(x).length; y++ ){
					temImagem = false;
					if ( outro.getMarcaXModelos().get(x)[y] != null ){
						for ( int z=0; z<this.marcas.size(); z++ ){
							for ( int w=1; w<this.marcas.get(z).length; w++ ){
								if ( this.marcas.get(z)[w] != null ){
									if ( outro.getMarcaXModelos().get(x)[y].equals(this.marcas.get(z)[w]) ){
										temImagem = true;
									}
								}
							}
						}
						if ( !temImagem) {
							marcasModelosIguais = false;
							break;
						}
					}
				}
			}
		}
		else{
			marcasModelosIguais = false;
		}
		
		return ( this.potencia == outro.getPotencia() && segurosIguais && acessoriosIguais && marcasModelosIguais );
	}
	
	/**
	 * Retorna qual a potencia os veiculos que o plano oferece devem ter.
	 */
	public double getPotencia(){
		return this.potencia;
	}
	
	/**
	 * Determina uma nova potencia que os veiculos que o plano oferece devem ter.
	 */
	public void setPotencia(double potencia){
		this.potencia = potencia;
	}
	
	/**
	 * Retorna uma String com os atributos do Plano.
	 */
	@Override
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		for ( int i=0; i<this.marcas.size(); i++ ){
			sb.append(this.marcas.get(i)[0] + ":[");
			for ( int j=1; j<this.marcas.get(i).length; j++ ){
				if ( !( this.marcas.get(i)[j] == null ) ){
					sb.append(this.marcas.get(i)[j]);
					if ( (j+1) < this.marcas.get(i).length ){
						sb.append(", ");
					}
				}
			}
			sb.append("]");
			if ( (i+1) < this.marcas.size() ){
				sb.append(", ");
			}
			else{
				sb.append("}");
			}
		}
		return sb.toString();
	}
}